<?php 

require_once("Log.class.php");
require_once("MySQLDatabase.class.php");
require_once("Database.class.php");

class EInvalidColumn extends Exception {
	public function __toString() {
		list($table,$column) = explode(":",$this->message);
		return $column." column could not be found in ".$table." table";
	}
}

abstract class DBTable {

protected $DB;
private $tablename;
private $tmprow;
protected $row;
private $columnheadings;

	public function __construct($table="") {
		if ($table) { 
			$this->setTable($table);
		} else {
			$this->setTable(get_class($this));
		}
		$this->DB = new Database();
		$this->prepRow();	
	}

	 public function prepRow() {
		$this->row = array();
		$this->columnheadings= $this->getColumnHeadings();
		$this->row = $this->columnheadings;
	}

	 public function getColumnHeadings() {
		$db = new Database();
		$db->query("desc ".$this->getTable());
	 	while ($field = $db->getNextRow()) {
		$fields[$field[0]] = "";
		}
		return $fields;
	 }

        public function isFieldValid($field) {
                if (array_key_exists($field,$this->row)) return true;

        }
	 public function clear() {
		$this->prepRow();
	 }

	 public function __get($column) {
		if (array_key_exists($column,$this->row)) {
			//print_r($this->row);
			return $this->row[$column];
		} else {
				$this->reportError($this->makeFieldSafe($this->tablename.":".$column));
				throw new EInvalidColumn($this->makeFieldSafe($this->tablename.":".$column));
			}
	 }	

	 public function __set($column,$value) {
		if (array_key_exists($column,$this->row)) {
			if (method_exists($this,"onChange".$column)) {
				$func = "onChange".$column; 
				if ($v = $this->$func($value)) {
					$this->row[$column] = $v;
				} else {
					$this->row[$column]=$value;
				}
			}else{
				$this->row[$column]=$value;
			}
		} else {
			$this->reportError($this->makeFieldSafe($this->tablename.":".$column));
			throw new EInvalidColumn($this->makeFieldSafe($this->tablename.":".$column));
		}
	 }

	

	 public function __call($method,$args) {
		//print_r($args);
		if (preg_match("/find(.*)/",$method,$matches)) {
			if (array_key_exists($matches[1],$this->row)) {
				$this->DB->query("SELECT * FROM ".$this->getTable()." where ".$matches[1]."='".$args[0]."'");
			}
			if ($this->DB->RowCount == 1) {
				$this->getNext();
			}
		}
	 }
	
	 public function selectAll() {
		$this->DB->query("SELECT * FROM ".$this->getTable()." ORDER BY ID");
		return $this->DB->RowCount;
	}
	
	 public function update() {
		//print_r($this->row);
		if (method_exists($this,"preUpdate")) {
				$this->preUpdate();
			}
		if (!$this->row['ID']||strlen($this->row['ID']) == 0) {
			$this->DB->query("INSERT INTO ".$this->getTable()." () values ()");
			$this->row['ID'] = $this->DB->LastID;
		} 
		$this->tmprow = $this->DB->query("SELECT * FROM ".$this->getTable()." where ID='".$this->row['ID']."'");
		$this->tmprow = $this->DB->getNextRow();
		$sql = "UPDATE ".$this->getTable()." set "; 
		$columnmods=0;
		foreach ($this->row as $column => $value) {
			if (($this->row[$column] != $this->tmprow[$column]) && array_key_exists($column,$this->columnheadings)) {
				$columnmods++;
				if ($value != "NULL") {
					$value = "'".mysql_escape_string($value)."'";
				}
				$sql .= $column."=".$value.",";
			}
			//$this->DB->query("UPDATE ".$this->getTable()." set ".$column."='".$value."' where ID='".$this->row['ID']."'");
		}
		$sql = rtrim($sql,",");
		$sql .= " WHERE ID='".$this->row['ID']."'";
		if ($columnmods >=1) {
			try {
				$this->DB->query($sql);
				//print $sql;
			} 
			catch (EDatabaseQueryError $e) {
				die("DatabaseQueryError");
			}
		//	print $sql;
		}
		if (method_exists($this,"postUpdate")) {
			$this->postUpdate();
		}
	 }
	
	public function delete()
	{
		if ($this->ID) {
			if (method_exists($this,"beforeDelete"))
				if ($this->beforeDelete()) return false;
			$db = new Database();
			$db->query("DELETE FROM ".$this->getTable()." WHERE ID='$this->ID'");
			if (method_exists($this,"afterDelete"))
				$this->afterDelete();
			$this->clear();
		}
	}
	
	public function getNext() {
		if ($this->row = $this->DB->getNextRow()) {
			//print_r($this->row);
			//print "<hr />";
			return true;
		} else {
			$this->prepRow();
			return false;
		}
	 }
	
	 public function setTable($table) {
		$this->tablename = $table;
	 }
	
	 public function getTable() {
		return $this->tablename;
	 }
	
	public function makeStringDisplayable($string)
	{
		$find[] = 'Ã¢â¬Å';  // left side double smart quote
		$find[] = 'Ã¢â¬Â';  // right side double smart quote
		$find[] = 'Ã¢â¬â¢';  // left side double smart quote
		$find[] = 'Ã¢â¬Ë';  // right side double smart quote
		$find[] = 'Ã¢â¬Ë';  // left side single smart quote
		$find[] = 'Ã¢â¬â¢';  // right side single smart quote
		$find[] = 'Ã¢â¬Â¦';  // elipsis
		$find[] = chr(226).chr(128).chr(147); //$find[] = 'Ã¢â¬â';  // em dash
		$find[] = chr(222); // some weird MacOS X apostrophe
		
		$replace[] = '\"';
		$replace[] = '\"';
		$replace[] = "'";
		$replace[] = "'";
		$replace[] = "'";
		$replace[] = "'";
		$replace[] = "...";
		$replace[] = "-";
		$replace[] = "'";
		return htmlentities(stripslashes(str_replace($find, $replace, $string)), ENT_COMPAT);
	}

	private function reversehtmlentities($string)
	{
		$trans_tbl = get_html_translation_table(HTML_ENTITIES);
		$trans_tbl = array_flip($trans_tbl);
		$ret = strtr($string, $trans_tbl);
		return preg_replace('/&#(\d+);/me' , "chr('\1')" , $ret);
	}

	public function makeFieldSafe($string)
	{
		return $this->DB->makeFieldSafe($string);
	}
	
	public function emptyTableCompletely($confirm)
	{
		if ($confirm == $this->tablename) {
			$this->DB->query("TRUNCATE TABLE ".$this->tablename);
			$this->clear();
		}
		else {
			die('Attempt to clear '.$this->tablename.' without confirming correctly');
		}
	}
		
	protected function reportError ($ErrorText="")
	{
		$callers = debug_backtrace();
		array_shift($callers);
		foreach ($callers as $item) {
			$backtrace .= "$item[file]:$item[line]\n";
			$backtrace .= "$item[function](";
			$args = 0;
			foreach ($item['args'] as $arg) {
				if ($args)
					$backtrace .= ", ";
				$backtrace .= "'$arg'";
				$args++;
			}
			$backtrace .= ");\n\n";
		}
		try {
			foreach ($_POST as $key=>$value) {
				$post .= "\$$key = $value\n";
			}
			foreach ($_GET as $key=>$value) {
				$get .= "\$$key = $value\n";
			}
			foreach ($_SERVER as $key=>$value) {
				$server .= "\$$key = $value\n";
			}
			foreach ($_SESSION as $key=>$value) {
				if (!is_object($value)) $session .= "\$$key = $value\n";
			}
		}
		catch (Exception $e) {
			// Do nothing
		}

		mail('nobody@noreply.com', $this->getSiteTitle()." Database error",
			$this->reportTitle("Error").wordwrap($ErrorText,70)."\n".
			$this->reportTitle("Function Backtrace")."$backtrace\n\n".
			$this->reportTitle("Post")."$post\n\n".
			$this->reportTitle("Get")."$get\n\n".
			$this->reportTitle("Server")."$server".
			$this->reportTitle("Session")."$session",
			"From: ".$this->getSiteTitle()." Database Problem <chris@rightboat.com>");
	}
}
